package com.nulldev.util.data.Arrays.maps;

import java.util.Collection;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.DoubleBinaryOperator;
import java.util.function.Function;
import java.util.function.IntBinaryOperator;
import java.util.function.LongBinaryOperator;
import java.util.function.ToDoubleBiFunction;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntBiFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongBiFunction;
import java.util.function.ToLongFunction;

import com.nulldev.util.JVM.Arguments;
import com.nulldev.util.VariableAPI.MathUtil;

public class FastHashMap<K, V> extends ConcurrentHashMap<K, V> {
	/**
	 * 
	 */
	private static final long serialVersionUID = 7807867394834569560L;

	private final static boolean ENABLE_FAST_FOR_READ_OPS = Arguments.hasArgument("--FastHashMap.enableFastRead");
	private final static boolean USE_LAZY_SET_FOR_PUT = Arguments.hasArgument("--FastHashMap.enableLazyPut");
	private final AtomicReference<ConcurrentHashMap<K, V>> map;
	private final boolean enableFast;

	public FastHashMap() {
		super(0);
		this.enableFast = false;
		this.map = new AtomicReference<ConcurrentHashMap<K, V>>(new ConcurrentHashMap<K, V>());
	}

	public FastHashMap(final boolean fast) {
		super(0);
		this.enableFast = fast;
		this.map = new AtomicReference<ConcurrentHashMap<K, V>>(new ConcurrentHashMap<K, V>());
	}

	public FastHashMap(final int cap) {
		super(0);
		this.enableFast = false;
		this.map = new AtomicReference<ConcurrentHashMap<K, V>>(new ConcurrentHashMap<K, V>(cap));
	}

	public FastHashMap(final int cap, final boolean fast) {
		super(0);
		this.enableFast = fast;
		this.map = new AtomicReference<ConcurrentHashMap<K, V>>(new ConcurrentHashMap<K, V>(cap));
	}

	public FastHashMap(final Map<? extends K, ? extends V> map) {
		super(0);
		this.enableFast = false;
		this.map = new AtomicReference<ConcurrentHashMap<K, V>>(new ConcurrentHashMap<K, V>(map));
	}

	public FastHashMap(final Map<? extends K, ? extends V> map, final boolean fast) {
		super(0);
		this.enableFast = fast;
		this.map = new AtomicReference<ConcurrentHashMap<K, V>>(new ConcurrentHashMap<K, V>(map));
	}

	@Override
	public void clear() {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			o.clear();
			this.map.lazySet(o);
		} else
			this.map.get().clear();
	}

	@Override
	public V get(final Object index) {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.get(index);
		} else
			return this.map.get().get(index);
	}

	@Override
	public V put(K key, V value) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final V r = o.put(key, value);
			if (USE_LAZY_SET_FOR_PUT)
				this.map.lazySet(o);
			else
				this.map.set(o);
			return r;
		} else
			return this.map.get().put(key, value);
	}

	@Override
	public boolean containsKey(Object key) {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.containsKey(key);
		} else
			return this.map.get().containsKey(key);
	}

	@Override
	public boolean containsValue(Object value) {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.containsValue(value);
		} else
			return this.map.get().containsValue(value);
	}

	@Override
	public int size() {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.size();
		} else
			return this.map.get().size();
	}

	@Override
	public boolean contains(Object value) {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.contains(value);
		} else
			return this.map.get().contains(value);
	}

	@Override
	public void forEach(BiConsumer<? super K, ? super V> action) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			o.forEach(action);
			this.map.lazySet(o);
		} else
			this.map.get().forEach(action);
	}

	@Override
	public void forEach(long parallelismThreshold, BiConsumer<? super K, ? super V> action) {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			o.forEach(parallelismThreshold, action);
			this.map.lazySet(o);
		} else
			this.map.get().forEach(parallelismThreshold, action);
	}

	@Override
	public <U> void forEach(long parallelismThreshold, BiFunction<? super K, ? super V, ? extends U> transformer, Consumer<? super U> action) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			o.forEach(parallelismThreshold, transformer, action);
			this.map.lazySet(o);
		} else
			this.map.get().forEach(parallelismThreshold, transformer, action);
	}

	@Override
	public void forEachEntry(long parallelismThreshold, Consumer<? super Entry<K, V>> action) {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			o.forEachEntry(parallelismThreshold, action);
			this.map.lazySet(o);
		} else
			this.map.get().forEachEntry(parallelismThreshold, action);
	}

	@Override
	public <U> void forEachEntry(long parallelismThreshold, Function<Entry<K, V>, ? extends U> transformer, Consumer<? super U> action) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			o.forEachEntry(parallelismThreshold, transformer, action);
			this.map.lazySet(o);
		} else
			this.map.get().forEachEntry(parallelismThreshold, transformer, action);
	}

	@Override
	public void forEachKey(long parallelismThreshold, Consumer<? super K> action) {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			o.forEachKey(parallelismThreshold, action);
			this.map.lazySet(o);
		} else
			this.map.get().forEachKey(parallelismThreshold, action);
	}

	@Override
	public <U> void forEachKey(long parallelismThreshold, Function<? super K, ? extends U> transformer, Consumer<? super U> action) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			o.forEachKey(parallelismThreshold, transformer, action);
			this.map.lazySet(o);
		} else
			this.map.get().forEachKey(parallelismThreshold, transformer, action);
	}

	@Override
	public void forEachValue(long parallelismThreshold, Consumer<? super V> action) {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			o.forEachValue(parallelismThreshold, action);
			this.map.lazySet(o);
		} else
			this.map.get().forEachValue(parallelismThreshold, action);
	}

	@Override
	public <U> void forEachValue(long parallelismThreshold, Function<? super V, ? extends U> transformer, Consumer<? super U> action) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			o.forEachValue(parallelismThreshold, transformer, action);
			this.map.lazySet(o);
		} else
			this.map.get().forEachValue(parallelismThreshold, transformer, action);
	}

	@Override
	public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final V r = o.compute(key, remappingFunction);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().compute(key, remappingFunction);
	}

	@Override
	public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final V r = o.computeIfAbsent(key, mappingFunction);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().computeIfAbsent(key, mappingFunction);
	}

	@Override
	public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final V r = o.computeIfPresent(key, remappingFunction);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().computeIfPresent(key, remappingFunction);
	}

	@Override
	public V getOrDefault(Object key, V defaultValue) {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.getOrDefault(key, defaultValue);
		} else
			return this.map.get().getOrDefault(key, defaultValue);
	}

	@Override
	public long mappingCount() {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.mappingCount();
		} else
			return this.map.get().mappingCount();
	}

	@Override
	public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final V r = o.merge(key, value, remappingFunction);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().merge(key, value, remappingFunction);
	}

	@Override
	public boolean isEmpty() {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.isEmpty();
		} else
			return this.map.get().isEmpty();
	}

	@Override
	public V putIfAbsent(K key, V value) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.putIfAbsent(key, value);
		} else
			return this.map.get().putIfAbsent(key, value);
	}

	@Override
	public Enumeration<V> elements() {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.elements();
		} else
			return this.map.get().elements();
	}

	@Override
	public Set<Entry<K, V>> entrySet() {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.entrySet();
		} else
			return this.map.get().entrySet();
	}

	@Override
	public Enumeration<K> keys() {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.keys();
		} else
			return this.map.get().keys();
	}

	@Override
	public Collection<V> values() {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.values();
		} else
			return this.map.get().values();
	}

	@Override
	public KeySetView<K, V> keySet() {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.keySet();
		} else
			return this.map.get().keySet();
	}

	@Override
	public KeySetView<K, V> keySet(V mappedValue) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.keySet(mappedValue);
		} else
			return this.map.get().keySet(mappedValue);
	}

	@Override
	public void putAll(Map<? extends K, ? extends V> m) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			o.putAll(m);
			this.map.lazySet(o);
		} else
			this.map.get().keySet();
	}

	@Override
	public V remove(Object key) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final V r = o.remove(key);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().remove(key);
	}

	@Override
	public boolean remove(Object key, Object value) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final boolean r = o.remove(key, value);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().remove(key, value);
	}

	@Override
	public V replace(K key, V value) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final V r = o.replace(key, value);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().replace(key, value);
	}

	@Override
	public boolean replace(K key, V oldValue, V newValue) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final boolean r = o.replace(key, oldValue, newValue);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().replace(key, oldValue, newValue);
	}

	@Override
	public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			o.replaceAll(function);
			this.map.lazySet(o);
		} else
			this.map.get().replaceAll(function);
	}

	@Override
	public <U> U reduce(long parallelismThreshold, BiFunction<? super K, ? super V, ? extends U> transformer,
			BiFunction<? super U, ? super U, ? extends U> reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final U r = o.reduce(parallelismThreshold, transformer, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduce(parallelismThreshold, transformer, reducer);
	}

	@Override
	public Entry<K, V> reduceEntries(long parallelismThreshold, BiFunction<Entry<K, V>, Entry<K, V>, ? extends Entry<K, V>> reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final Entry<K, V> r = o.reduceEntries(parallelismThreshold, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceEntries(parallelismThreshold, reducer);
	}

	@Override
	public <U> U reduceEntries(long parallelismThreshold, Function<Entry<K, V>, ? extends U> transformer,
			BiFunction<? super U, ? super U, ? extends U> reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final U r = o.reduceEntries(parallelismThreshold, transformer, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceEntries(parallelismThreshold, transformer, reducer);
	}

	@Override
	public double reduceEntriesToDouble(long parallelismThreshold, ToDoubleFunction<Entry<K, V>> transformer, double basis, DoubleBinaryOperator reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final double r = o.reduceEntriesToDouble(parallelismThreshold, transformer, basis, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceEntriesToDouble(parallelismThreshold, transformer, basis, reducer);
	}

	@Override
	public int reduceEntriesToInt(long parallelismThreshold, ToIntFunction<Entry<K, V>> transformer, int basis, IntBinaryOperator reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final int r = o.reduceEntriesToInt(parallelismThreshold, transformer, basis, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceEntriesToInt(parallelismThreshold, transformer, basis, reducer);
	}

	@Override
	public long reduceEntriesToLong(long parallelismThreshold, ToLongFunction<Entry<K, V>> transformer, long basis, LongBinaryOperator reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final long r = o.reduceEntriesToLong(parallelismThreshold, transformer, basis, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceEntriesToLong(parallelismThreshold, transformer, basis, reducer);
	}

	@Override
	public K reduceKeys(long parallelismThreshold, BiFunction<? super K, ? super K, ? extends K> reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final K r = o.reduceKeys(parallelismThreshold, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceKeys(parallelismThreshold, reducer);
	}

	@Override
	public <U> U reduceKeys(long parallelismThreshold, Function<? super K, ? extends U> transformer, BiFunction<? super U, ? super U, ? extends U> reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final U r = o.reduceKeys(parallelismThreshold, transformer, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceKeys(parallelismThreshold, transformer, reducer);
	}

	@Override
	public double reduceKeysToDouble(long parallelismThreshold, ToDoubleFunction<? super K> transformer, double basis, DoubleBinaryOperator reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final double r = o.reduceKeysToDouble(parallelismThreshold, transformer, basis, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceKeysToDouble(parallelismThreshold, transformer, basis, reducer);
	}

	@Override
	public int reduceKeysToInt(long parallelismThreshold, ToIntFunction<? super K> transformer, int basis, IntBinaryOperator reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final int r = o.reduceKeysToInt(parallelismThreshold, transformer, basis, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceKeysToInt(parallelismThreshold, transformer, basis, reducer);
	}

	@Override
	public long reduceKeysToLong(long parallelismThreshold, ToLongFunction<? super K> transformer, long basis, LongBinaryOperator reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final long r = o.reduceKeysToLong(parallelismThreshold, transformer, basis, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceKeysToLong(parallelismThreshold, transformer, basis, reducer);
	}

	@Override
	public double reduceToDouble(long parallelismThreshold, ToDoubleBiFunction<? super K, ? super V> transformer, double basis, DoubleBinaryOperator reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final double r = o.reduceToDouble(parallelismThreshold, transformer, basis, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceToDouble(parallelismThreshold, transformer, basis, reducer);
	}

	@Override
	public int reduceToInt(long parallelismThreshold, ToIntBiFunction<? super K, ? super V> transformer, int basis, IntBinaryOperator reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final int r = o.reduceToInt(parallelismThreshold, transformer, basis, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceToInt(parallelismThreshold, transformer, basis, reducer);
	}

	@Override
	public long reduceToLong(long parallelismThreshold, ToLongBiFunction<? super K, ? super V> transformer, long basis, LongBinaryOperator reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final long r = o.reduceToLong(parallelismThreshold, transformer, basis, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceToLong(parallelismThreshold, transformer, basis, reducer);
	}

	@Override
	public V reduceValues(long parallelismThreshold, BiFunction<? super V, ? super V, ? extends V> reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final V r = o.reduceValues(parallelismThreshold, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceValues(parallelismThreshold, reducer);
	}

	@Override
	public <U> U reduceValues(long parallelismThreshold, Function<? super V, ? extends U> transformer, BiFunction<? super U, ? super U, ? extends U> reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final U r = o.reduceValues(parallelismThreshold, transformer, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceValues(parallelismThreshold, transformer, reducer);
	}

	@Override
	public double reduceValuesToDouble(long parallelismThreshold, ToDoubleFunction<? super V> transformer, double basis, DoubleBinaryOperator reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final double r = o.reduceValuesToDouble(parallelismThreshold, transformer, basis, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceValuesToDouble(parallelismThreshold, transformer, basis, reducer);
	}

	@Override
	public int reduceValuesToInt(long parallelismThreshold, ToIntFunction<? super V> transformer, int basis, IntBinaryOperator reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final int r = o.reduceValuesToInt(parallelismThreshold, transformer, basis, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceValuesToInt(parallelismThreshold, transformer, basis, reducer);
	}

	@Override
	public long reduceValuesToLong(long parallelismThreshold, ToLongFunction<? super V> transformer, long basis, LongBinaryOperator reducer) {
		if (this.enableFast) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			final long r = o.reduceValuesToLong(parallelismThreshold, transformer, basis, reducer);
			this.map.lazySet(o);
			return r;
		} else
			return this.map.get().reduceValuesToLong(parallelismThreshold, transformer, basis, reducer);
	}

	@Override
	public <U> U search(long parallelismThreshold, BiFunction<? super K, ? super V, ? extends U> searchFunction) {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.search(parallelismThreshold, searchFunction);
		} else
			return this.map.get().search(parallelismThreshold, searchFunction);
	}

	@Override
	public <U> U searchEntries(long parallelismThreshold, Function<Entry<K, V>, ? extends U> searchFunction) {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.searchEntries(parallelismThreshold, searchFunction);
		} else
			return this.map.get().searchEntries(parallelismThreshold, searchFunction);
	}

	@Override
	public <U> U searchKeys(long parallelismThreshold, Function<? super K, ? extends U> searchFunction) {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.searchKeys(parallelismThreshold, searchFunction);
		} else
			return this.map.get().searchKeys(parallelismThreshold, searchFunction);
	}

	@Override
	public <U> U searchValues(long parallelismThreshold, Function<? super V, ? extends U> searchFunction) {
		if (this.enableFast && ENABLE_FAST_FOR_READ_OPS) {
			final ConcurrentHashMap<K, V> o = new ConcurrentHashMap<K, V>(this.map.get());
			return o.searchValues(parallelismThreshold, searchFunction);
		} else
			return this.map.get().searchValues(parallelismThreshold, searchFunction);
	}

	@Override
	public String toString() {
		return "FastHashMap@" + MathUtil.toHex(super.hashCode()) + "{" + this.map.get().toString() + "}";
	}
}
